import base64
import io
import shutil
import tempfile
import zipfile
from datetime import datetime
from io import BytesIO
from pathlib import Path

import pandas as pd
from flask import abort, jsonify, request, current_app, app, send_from_directory, make_response, send_file, json
from flask_restful import Resource, reqparse
import os
from werkzeug.utils import safe_join, secure_filename
from project_name.base import Admin_DIR, User_DIR, source_file

from project_name.utils import get_real_path, get_json_from_excel


class CreateFolderResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('path', type=str, required=True, help='path is required')
        parser.add_argument('folderName', type=str, required=True, help='folderName is required')
        data = parser.parse_args()

        try:
            base_path = data['path']
            folder_name = secure_filename(data['folderName'])

            if '..' in base_path or '..' in folder_name:
                return jsonify({"status": "error", "message": "非法路径"}), 403

            full_path = os.path.join(Admin_DIR, base_path, folder_name)

            if os.path.exists(full_path):
                return jsonify({"status": "error", "message": "文件夹已存在"}), 400

            os.makedirs(full_path)
            return jsonify({"status": "success", "message": "创建成功", "path": full_path})
        except Exception as e:
            return jsonify({"status": "error", "message": str(e)}), 500


class UpdateFolderNameResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('path', type=str, required=True, help='path is required')
        parser.add_argument('oldFolderName', type=str, required=True, help='oldFolderName is required')
        parser.add_argument('newFolderName', type=str, required=True, help='folderName is required')
        data = parser.parse_args()
        try:
            path = get_real_path(data['path'], ",")
            old_folder_name = secure_filename(data['oldFolderName'])
            new_folder_name = secure_filename(data['newFolderName'])

            old_folder_path = Path(current_app.static_folder, path, old_folder_name)
            new_folder_path = Path(current_app.static_folder, path, new_folder_name)
            if not old_folder_path.exists():
                return jsonify({"code": 404, "message": "旧文件夹不存在", "data": None})

            if new_folder_path.exists():
                return jsonify({"code": 400, "message": "新文件夹已存在", "data": None})

            old_folder_path.rename(new_folder_path)
            return jsonify({"code": 200, "message": "修改成功", "data": None})

        except Exception as e:
            return jsonify({"code": 500, "message": str(e), "data": None})


class UploadFileResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        # Admin/..../....
        parser.add_argument('currentPath', type=str, required=True)
        parser.add_argument('files', type=list, location='json', required=True)
        args = parser.parse_args()

        try:
            current_path = get_real_path(args['currentPath'], ',')
            # 确保目录存在
            os.makedirs(os.path.join(current_app.static_folder, current_path), exist_ok=True)

            for file_data in args['files']:
                file_name = file_data['name']
                file_path = get_real_path(file_data['relativePath'], '/')
                base64_data = file_data['data']

                # 解码Base64并保存文件
                file_bytes = base64.b64decode(base64_data)
                save_path = os.path.join(current_app.static_folder, current_path, file_path)
                os.makedirs(os.path.dirname(save_path), exist_ok=True)
                with open(os.path.join(save_path, file_name), 'wb') as f:
                    f.write(file_bytes)

            return {'code': 200, 'message': '文件上传成功'}

        except Exception as e:
            return {'code': 400, 'message': str(e)}


class DeleteFileResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('path', type=str, required=True, help='path is required')
        parser.add_argument('type', type=str, required=True, help='type is required')
        data = parser.parse_args()

        try:
            full_path = os.path.join(Admin_DIR, data['path'])

            if not os.path.exists(full_path):
                return jsonify({"status": "error", "message": "文件不存在"}), 404

            is_dir = os.path.isdir(full_path)
            if (data['type'] == 'file' and is_dir) or (data['type'] == 'directory' and not is_dir):
                return jsonify({"status": "error", "message": "类型不匹配"}), 400

            if is_dir:
                shutil.rmtree(full_path)
            else:
                os.remove(full_path)

            return jsonify({"status": "success", "message": "删除成功"})
        except Exception as e:
            return jsonify({"status": "error", "message": str(e)}), 500


class DownloadFileResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('path', type=str, required=True, help='path is required')
        parser.add_argument('filename', type=str, required=True, help='type is required')
        parser.add_argument('parentPath', type=str, required=True, help='parentPath is required')
        data = parser.parse_args()
        path = data['path']
        filename = data['filename']
        parentPath = data['parentPath']

        # 指定文件名和静态目录
        path = get_real_path(path, ',')
        file_path = Path(current_app.config['user_dir'], path, parentPath, filename)

        if not file_path.exists():
            return {"code": 404, "message": "文件不存在"}

        return send_from_directory(
            directory=file_path.parent,
            path=file_path.name,
            as_attachment=True,
            download_name=filename,
        )


class DownloadMultipleFilesResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('path', type=str, required=True, help='path is required')
        parser.add_argument('fileNames', type=str, required=True, help='需要下载的文件路径列表')
        args = parser.parse_args()

        file_names = args['fileNames'].split(',')
        file_path = get_real_path(args['path'], ',')

        base_dir = Path(current_app.config['user_dir']) / file_path
        zip_name = f'{base_dir.parts[-1]}.zip'
        zip_path = Path(base_dir, zip_name)
        valid_files = []

        for patient_path in base_dir.iterdir():
            for file_name in file_names:
                if patient_path.name + '.xlsx' == file_name:
                    excel_file_path = Path(patient_path, file_name)
                    if excel_file_path.is_file() and excel_file_path.suffix in ['.xlsx', '.xls']:
                        valid_files.append(excel_file_path)
                    else:
                        return {"code": 403, "message": f"非法路径或文件不存在: {file_path}"}, 403

        if not valid_files:
            return {"code": 404, "message": "没有有效的文件可下载"}, 404

        # 确保临时ZIP文件不存在
        if zip_path.exists():
            try:
                zip_path.unlink()
            except:
                pass

        with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
            for file_path in valid_files:
                if not os.path.exists(file_path):
                    raise FileNotFoundError(f"文件不存在: {file_path}")

                # 在ZIP文件中使用相对路径存储文件
                arcname = os.path.basename(file_path)
                zipf.write(file_path, arcname)

        if not zip_path.exists():
            return {"code": 500, "message": "文件压缩失败"}

        response = send_from_directory(
            directory=zip_path.parent,
            path=zip_path.name,
            as_attachment=True,
            download_name=zip_name,
        )

        # 添加适当的头信息
        response.headers['Content-Type'] = 'application/zip'
        response.headers['Content-Disposition'] = f'attachment; filename={zip_name}'

        return response


class batchDownloadJSONResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('path', type=str, required=True, help='path is required')
        parser.add_argument('fileNames', type=str, required=True, help='需要下载的文件路径列表')
        args = parser.parse_args()

        file_names = args['fileNames'].split(',')
        file_path = get_real_path(args['path'], ',')

        base_dir = Path(current_app.config['user_dir']) / file_path
        zip_name = f'{base_dir.parts[-1]}.zip'

        json_data = []
        for patient_path in base_dir.iterdir():
            for file_name in file_names:
                if patient_path.name + '.xlsx' == file_name:
                    excel_file_path = Path(patient_path, file_name)
                    if excel_file_path.is_file() and excel_file_path.suffix in ['.xlsx', '.xls']:
                        data = get_json_from_excel(excel_file_path)
                        json_data.append({'filename': patient_path.name, 'data': data})

                    else:
                        return {"code": 403, "message": f"非法路径或文件不存在: {file_path}"}, 403

        # 创建内存中的ZIP文件
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
            # 遍历每个数组元素
            for sub_array in json_data:
                # 为每个子数组创建JSON文件
                filename = f"{sub_array['filename']}.json"
                json_str = json.dumps(sub_array['data'], indent=2, ensure_ascii=False)
                zip_file.writestr(filename, json_str.encode('utf-8'))

            # 添加元数据文件
            # metadata = {
            #     "total_files": len(json_data),
            #     "total_records": sum(len(arr) for arr in json_data),
            #     "generated_at": datetime.now().isoformat(),
            #     "file_list": [f"data_{i}.json" for i in range(1, len(json_data) + 1)]
            # }
            # zip_file.writestr("_metadata.json", json.dumps(metadata, indent=2))

        # 准备响应
        zip_buffer.seek(0)
        response = make_response(zip_buffer.getvalue())

        # 设置响应头
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        response.headers['Content-Type'] = 'application/zip'
        response.headers[
            'Content-Disposition'] = f'attachment; filename="array_elements_{timestamp}.zip"'

        return response


class SendFileResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('users', type=str, location='json', required=True, help='user is required')
        parser.add_argument('filePaths', type=str, location='json', required=True, help='filePath is required')
        parser.add_argument('fileNames', type=str, location='json', required=True, help='fileNames is required')
        data = parser.parse_args()

        try:
            users = data['users'].split(",")
            filePath = get_real_path(data['filePaths'], ',')
            fileNames = data['fileNames'].split(",")

            # 构建静态资源目录中的完整路径
            full_source_path = Path(current_app.static_folder, filePath)
            # 验证目录是否合格
            for path in fileNames:
                target_path = Path(full_source_path, path)
                for path1 in target_path.iterdir():
                    if path1.is_dir():
                        for path2 in path1.iterdir():
                            if path2.suffix not in ['.jpeg', '.jpg', '.png']:
                                return jsonify({
                                    "code": 400,
                                    "message": "文件目录不合格，请保证子目录下是患者的文件夹",
                                    "data": {
                                        "path": str(path2),
                                        "exists": True
                                    }
                                })

            # 如果目录存在，返回错误信息
            for user in users:
                for file in fileNames:
                    user_dir = Path(current_app.static_folder, "User", user, file)
                    # 检查路径是否已存在于用户目录中
                    if user_dir.exists():
                        return jsonify({
                            "code": 400,
                            "message": "文件夹已存在",
                            "data": {
                                "path": str(user_dir),
                                "exists": True
                            }
                        })

            # 构建用户目标目录
            for user in users:
                for file in fileNames:
                    user_dir = Path(current_app.static_folder, "User", user, file)
                    source_path = Path(full_source_path, file)
                    # 复制源路径下的所有内容到用户目录
                    if os.path.isfile(source_path):
                        shutil.copy2(source_path, user_dir)
                    elif os.path.isdir(source_path):
                        shutil.copytree(source_path, user_dir)

            return jsonify({
                "code": 200,
                "message": "文件/文件夹发送成功",
                "data": ""
            })

        except Exception as e:
            current_app.logger.error(f"文件操作失败: {str(e)}")
            return jsonify({"code": 500, "message": f"服务器错误: {str(e)}"})


class GetExcelFileListResource(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('path', type=str, location='json', required=True, help='user is required')
        parser.add_argument('username', type=str, location='json', required=True, help='username is required')
        data = parser.parse_args()
        try:
            username = data['username']
            path = get_real_path(data['path'], ',')
            if path == os.sep:
                path = 'User'
            full_path = Path(current_app.static_folder, path)
            if not full_path.exists():
                return jsonify({"code": 400, "message": "路径不存在"})

            dirs = []
            if full_path.parts[-2] != username:
                for path in full_path.iterdir():
                    if path.is_dir():
                        dirs.append({
                            "name": path.name,
                            "type": "directory",
                        })
            else:
                for path in full_path.iterdir():
                    if path.is_dir():
                        for path1 in path.iterdir():
                            if path1.is_file() and path1.suffix in ['.xlsx', '.xls']:
                                dirs.append({
                                    "name": path1.name,
                                    "type": "excel",
                                    "parentPath": path1.parent.name,
                                })

            return jsonify({"code": 200, "data": dirs, "message": "success"})

        except Exception as e:
            return jsonify({"code": 500, "message": "{str(e)}"})


class TestResource(Resource):
    def get(self):
        print(current_app.config['resource_url'])
        return jsonify({"code": 200, "message": "服务已启动"})
